﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;

using Microsoft.WindowsAPICodePack.Dialogs;
using Microsoft.WindowsAPICodePack.Taskbar;

namespace SlideShowDFG2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        string                      _dataFileLocation;
        XDocument                   _dataFile;
        ObservableCollection<Album> _albums;
        FileLocationProtocol        _method;
        WebClient                   _client;
        RegistryHelper              _registry;

        bool _ignoreSavePrompt = false;
        string _tempFile = string.Empty;
        string _saveDir = string.Empty;

        bool _fileValid = true;

        public MainWindow()
        {
            InitializeComponent();
        }

        public static void SetTaskBarState(TaskbarProgressBarState state)
        {
            try
            {
                TaskbarManager.Instance.SetProgressState(state);
            }
            catch { }
        }

        public static void SetTaskBarProgress(int progress, int maxValue)
        {
            try
            {
                TaskbarManager.Instance.SetProgressValue(progress, maxValue);
            }
            catch { }
        }

        private void CloseMainWindowToStartupWindow()
        {
            _ignoreSavePrompt = true;
            StartupWindow window = new StartupWindow();
            window.Show();
            base.Close();
        }

        private void CreateAlbumTreeFromFile(string pathToXml)
        {
            _dataFile = XDocument.Load(_dataFileLocation);

            _albums = new ObservableCollection<Album>();

            foreach (XElement albumElement in _dataFile.Element("data").Elements("album"))
            {
                Album album = new Album();
                album.Description = albumElement.Attribute("description").Value;
                album.Title = albumElement.Attribute("title").Value;

                foreach (XElement slideElement in albumElement.Elements("slide"))
                {
                    Slide slide = new Slide();
                    slide.Description = slideElement.Attribute("description") == null ? string.Empty : slideElement.Attribute("description").Value;
                    slide.Source = slideElement.Attribute("source") == null ? string.Empty : slideElement.Attribute("source").Value;
                    slide.Thumbnail = slideElement.Attribute("thumbnail") == null ? string.Empty : slideElement.Attribute("thumbnail").Value;
                    slide.Title = slideElement.Attribute("title") == null ? string.Empty : slideElement.Attribute("title").Value;
                    album.Slides.Add(slide);
                }
                _albums.Add(album);
            }
        }

        private void CreateAlbumTreeFromString(string xml)
        {
            _dataFile = XDocument.Parse(xml);

           

            _albums = new ObservableCollection<Album>();

            foreach (XElement albumElement in _dataFile.Element("data").Elements("album"))
            {
                Album album = new Album();
                album.Description = albumElement.Attribute("description").Value;
                album.Title = albumElement.Attribute("title").Value;

                foreach (XElement slideElement in albumElement.Elements("slide"))
                {
                    Slide slide = new Slide();
                    slide.Description = slideElement.Attribute("description") == null ? string.Empty : slideElement.Attribute("description").Value;
                    slide.Source = slideElement.Attribute("source") == null ? string.Empty : slideElement.Attribute("source").Value;
                    slide.Thumbnail = slideElement.Attribute("thumbnail") == null ? string.Empty : slideElement.Attribute("thumbnail").Value;
                    slide.Title = slideElement.Attribute("title") == null ? string.Empty : slideElement.Attribute("title").Value;
                    album.Slides.Add(slide);
                }
                _albums.Add(album);
            }
        }

        private void ValidateDataFile(XDocument document)
        {
            XmlSchemaSet set = new XmlSchemaSet();
            set.Add("", XmlReader.Create(Assembly.GetAssembly(typeof(MainWindow)).GetManifestResourceStream("SlideShowDFG2.Data.xsd")));

            document.Validate(set, new ValidationEventHandler(XmlValidationErrorHandler));
        }

        private void XmlValidationErrorHandler(object sender, ValidationEventArgs e)
        {
            _fileValid = false;
        }
        
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _registry = new RegistryHelper();
            _method = (FileLocationProtocol)Enum.Parse(typeof(FileLocationProtocol), Application.Current.Properties["FileSystem"].ToString());
            if (_method == FileLocationProtocol.LocalFileSystem)
            {

                if ((StartupOptions)Enum.Parse(typeof(StartupOptions), Application.Current.Properties["StartupOptions"].ToString()) == StartupOptions.NewDataFile)
                {
                    if (Environment.OSVersion.Version.Major == 6)
                    {
                        CommonSaveFileDialog dialog = new CommonSaveFileDialog();
                        dialog.EnsureFileExists = true;
                        dialog.Filters.Add(new CommonFileDialogFilter("XML Docuements", "*.xml"));
                        dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                        dialog.OverwritePrompt = true;
                        dialog.ShowPlacesList = true;
                        dialog.Title = "Select Output Location";

                        if (dialog.ShowDialog() == CommonFileDialogResult.OK)
                        {
                            _dataFileLocation = dialog.FileName;
                            _dataFile = new XDocument();
                            _albums = new ObservableCollection<Album>();
                        }
                        else
                        {
                            CloseMainWindowToStartupWindow();
                        }
                        dialog.Dispose();
                    }
                }
                else
                {
                    if (Environment.OSVersion.Version.Major == 6)
                    {
                        CommonOpenFileDialog dialog = new CommonOpenFileDialog();
                        dialog.EnsureFileExists = true;
                        dialog.Filters.Add(new CommonFileDialogFilter("XML Documents", "*.xml"));
                        dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                        dialog.Multiselect = false;
                        dialog.ShowPlacesList = true;
                        dialog.Title = "Select Data File";

                        if (dialog.ShowDialog() == CommonFileDialogResult.OK)
                        {
                            _dataFileLocation = dialog.FileName;

                            CreateAlbumTreeFromFile(dialog.FileName);
                            ValidateDataFile(_dataFile);
                            if (!_fileValid)
                            {
                                MessageBox.Show("The selected data file is not a valid Slide.Show 2 data file.",
                                                "Invalid Data File", MessageBoxButton.OK, MessageBoxImage.Information);
                                CloseMainWindowToStartupWindow();
                                return;
                            }
                        }
                        else
                        {
                            CloseMainWindowToStartupWindow();
                        }
                        dialog.Dispose();
                    }
                }
                _saveDir = Path.GetDirectoryName(_dataFileLocation);
            }
            else
            {
                FtpConnectionWindow window = new FtpConnectionWindow();
                window.Owner = this;
                bool? result = window.ShowDialog();
                if (result != true)
                {
                    CloseMainWindowToStartupWindow();
                    return;
                }

                _client = WebClientHelper.GetNewInstance();

                if ((StartupOptions)Enum.Parse(typeof(StartupOptions), Application.Current.Properties["StartupOptions"].ToString()) == StartupOptions.NewDataFile)
                {
                    _albums = new ObservableCollection<Album>();
                    _dataFile = new XDocument();
                }
                else
                {   
                    
                    string rawData = string.Empty;
                    
                    try
                    {
                        rawData = _client.DownloadString(_registry.FtpDataFile);
                    }
                    catch (WebException d)
                    {
                  

                        MessageBox.Show(d.Message, "Download Error", MessageBoxButton.OK, MessageBoxImage.Error);

                        CloseMainWindowToStartupWindow();
                        return;
                    }

                    CreateAlbumTreeFromString(rawData);
                }
            }
            
            lvAlbums.ItemsSource = _albums;
            lblCurrentFile.Content = _dataFileLocation;
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (!_ignoreSavePrompt)
            {
                MessageBoxResult result = MessageBox.Show("Do you want to save changes?", "Save Changes?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);

                if (result == MessageBoxResult.Cancel)
                {
                    e.Cancel = true;
                }
                else if (result == MessageBoxResult.Yes)
                {
                    _dataFile.RemoveNodes();
                    _dataFile.Declaration = new XDeclaration("1.0", "utf-8", "yes");

                    XElement dataElement = new XElement("data");

                    foreach (Album album in _albums)
                    {
                        XElement albumElement = new XElement("album",
                                                                new XAttribute("description", album.Description),
                                                                new XAttribute("title", album.Title));
                        foreach (Slide slide in album.Slides)
                        {
                            XElement slideElement = new XElement("slide",
                                                                    new XAttribute("description", slide.Description),
                                                                    new XAttribute("link", slide.Link),
                                                                    new XAttribute("source", slide.Source),
                                                                    new XAttribute("title", slide.Title),
                                                                    new XAttribute("thumbnail", slide.Thumbnail));

                            albumElement.Add(slideElement);
                        }
                        dataElement.Add(albumElement);
                    }
                    _dataFile.Add(dataElement);
                    
                    if (_method == FileLocationProtocol.LocalFileSystem)
                    {
                        _dataFile.Save(_dataFileLocation);
                    }
                    else
                    {
                        try
                        {
                            _client.UploadString(_registry.FtpDataFile, _dataFile.ToString());
                            _client.Dispose();
                        }
                        catch
                        {
                            e.Cancel = true;
                            MessageBox.Show("Can't upload data file to server", "Upload Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                    }
                }
            }
        }

        private void btnAlbumEdit_Click(object sender, RoutedEventArgs e)
        {
            EditAlbumWindow window = new EditAlbumWindow(_albums[lvAlbums.SelectedIndex]);
            window.Owner = this;
            bool? result = window.ShowDialog();

            if (result == true)
            {
                _albums.RemoveAt(lvAlbums.SelectedIndex);
                _albums.Add(window.Album);
            }
        }

        private void btnAlbumDelete_Click(object sender, RoutedEventArgs e)
        {
            Album album = _albums[lvAlbums.SelectedIndex];
            MessageBoxResult result = MessageBox.Show("Are you sure that you want to remove the album " + album.Title + "?",
                                                    "Confirm Album Removal", MessageBoxButton.YesNo, MessageBoxImage.Question);
            if (result == MessageBoxResult.Yes)
            {
                bool removeAlbum = true;
                foreach (Slide slide in album.Slides)
                {
                    if (_method == FileLocationProtocol.LocalFileSystem)
                    {
                        string imgPath = Path.Combine(_dataFileLocation, slide.Source);
                        try
                        {
                            File.Delete(imgPath);
                        }
                        catch
                        {
                            removeAlbum = false;
                            MessageBox.Show("Can't delete slides in album", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                            break;
                        }
                    }
                    else
                    {
                        // This won't work
                        UriBuilder builder = new UriBuilder();
                        builder.Scheme = "ftp";
                        builder.Host = _registry.FtpHost;
                        builder.Port = _registry.FtpPort;
                        builder.Path = _registry.FtpSaveDir + slide.Source;
                        builder.UserName = _registry.FtpUserName;
                        builder.Password = _registry.FtpPassword;

                        NetworkCredential credentials = new NetworkCredential();
                        credentials.Password = _registry.FtpPassword;
                        credentials.UserName = _registry.FtpUserName;

                        FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(builder.Uri);
                        request.Credentials = credentials;
                        request.Method = WebRequestMethods.Ftp.DeleteFile;
                        request.GetRequestStream().Close();
                    }
                }
                if (removeAlbum)
                {
                    _albums.RemoveAt(lvAlbums.SelectedIndex);
                    lvSlides.SelectedIndex = -1;
                }
            }
        }

        private void btnAlbumNew_Click(object sender, RoutedEventArgs e)
        {
            EditAlbumWindow window = new EditAlbumWindow(new Album());
            window.Owner = this;
            bool? result = window.ShowDialog();

            if (result == true) _albums.Add(window.Album);
        }

        private void btnSlideNew_Click(object sender, RoutedEventArgs e)
        {
            EditSlideWindow window = new EditSlideWindow();
            window.Method = _method;
            window.Slide = new Slide();
            window.SaveDir = _saveDir;
            window.Owner = this;
            bool? result = window.ShowDialog();

            if (result == true) _albums[lvAlbums.SelectedIndex].Slides.Add(window.Slide);
        }

        private void btnSlideDelete_Click(object sender, RoutedEventArgs e)
        {
            Slide slide = _albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex];
            MessageBoxResult result = MessageBox.Show("Are you sure that you want to remove the slide " + slide.ToString() + "?",
                                                        "Confirm Slide Removal", MessageBoxButton.YesNo, MessageBoxImage.Question);
            if (result == MessageBoxResult.Yes)
            {
                if (_method == FileLocationProtocol.LocalFileSystem)
                {
                    try
                    {
                        File.Delete(Path.Combine(Path.GetDirectoryName(_dataFileLocation), slide.Source));
                        _albums[lvAlbums.SelectedIndex].Slides.RemoveAt(lvSlides.SelectedIndex);
                    }
                    catch
                    {
                        MessageBox.Show("Can't delete selected slide", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
                else
                {
                    // This won't work

                    UriBuilder builder = new UriBuilder();
                    builder.Scheme = "ftp";
                    builder.Host = _registry.FtpHost;
                    builder.Port = _registry.FtpPort;
                    builder.Path = _registry.FtpSaveDir + slide.Source;
                    builder.UserName = _registry.FtpUserName;
                    builder.Password = _registry.FtpPassword;

                    NetworkCredential credentials = new NetworkCredential();
                    credentials.Password = _registry.FtpPassword;
                    credentials.UserName = _registry.FtpUserName;
                   
                    FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(builder.Uri);
                    request.Credentials = new NetworkCredential(_registry.FtpUserName, _registry.FtpPassword);
                    request.Method = WebRequestMethods.Ftp.DeleteFile;
                    request.GetResponse().Close();

                    _albums[lvAlbums.SelectedIndex].Slides.RemoveAt(lvSlides.SelectedIndex);
                }
            }
        }

        private void btnSettings_Click(object sender, RoutedEventArgs e)
        {
            SettingsWindow window = new SettingsWindow();
            window.Owner = this;
            window.ShowDialog();
        }

        private void lvAlbums_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                btnAlbumEdit.IsEnabled = true;
                btnAlbumDelete.IsEnabled = true;
                btnSlideNew.IsEnabled = true;
                lvSlides.ItemsSource = _albums[lvAlbums.SelectedIndex].Slides;
            }
            catch { }
        }

        private void lvSlides_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            btnSlideDelete.IsEnabled = true;

            lblImgMsg.Content = null;
            try
            {
                spSlideDetails.DataContext = _albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex];
            }
            catch { } // Will catch ArgumentOutOfRangeException
            if (_method == FileLocationProtocol.LocalFileSystem)
            {
                if (!_albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].IsVideoFile())
                {
                    btnVideoPreview.IsEnabled = false;
                    try
                    {
                        BitmapImage source = new BitmapImage();
                        source.BeginInit();
                        source.UriSource = new Uri(Path.Combine(Path.GetDirectoryName(_dataFileLocation),
                                                    _albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].Source));
                        source.DecodePixelWidth = 200;
                        source.EndInit();
                        source.Freeze();
                        imgPreview.Source = source as ImageSource;
                    }
                    catch
                    {
                        imgPreview.Source = null;
                        lblImgMsg.Content = "Couldn't open image";
                    }
                }
                else
                {
                    btnVideoPreview.IsEnabled = true;
                }
            }
            else
            {
                if (_registry.FtpPreviewImage)
                {
                    if (string.IsNullOrEmpty(_albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].TempPreviewFile))
                    {
                        _client.DownloadFileCompleted += new AsyncCompletedEventHandler(_client_DownloadFileCompleted);

                        imgPreview.Source = null;
                        lblImgMsg.Content = "Loading...";
                        
                        string tempFile = Path.GetTempFileName();
                        _albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].TempPreviewFile = tempFile;
                        try
                        {
                            _client.DownloadFile(_albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].Source, tempFile);
                        }
                        catch
                        {
                            lblImgMsg.Content = "Can't Download Image";
                        }
                    }
                    else
                    {
                        BitmapImage image = new BitmapImage();
                        image.BeginInit();
                        image.DecodePixelWidth = 200;
                        image.UriSource = new Uri(_albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].TempPreviewFile);
                        image.EndInit();
                        image.Freeze();
                        imgPreview.Source = image as ImageSource;
                    }
                }
                else lblImgMsg.Content = "Image Preview Disabled";
            }
        }

        private void btnVideoPreview_Click(object sender, RoutedEventArgs e)
        {
            VideoPreviewWindow window = new VideoPreviewWindow();
            window.Method = _method;
            if (_method == FileLocationProtocol.LocalFileSystem)
            {
                window.SourceFile = Path.Combine(Path.GetDirectoryName(_dataFileLocation), _albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].Source);
            }
            else
            {
                window.SourceFile = _albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].Source;
            }
            window.ShowDialog();
        }

        private void _client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            // This is will not display the image, but the image does exist as a temp file
            if (!e.Cancelled)
            {
                lblImgMsg.Content = null;
                try
                {
                    BitmapImage image = new BitmapImage();
                    image.BeginInit();
                    image.DecodePixelWidth = 200;
                    image.UriSource = new Uri(_albums[lvAlbums.SelectedIndex].Slides[lvSlides.SelectedIndex].TempPreviewFile);
                    image.EndInit();
                    image.Freeze();
                    imgPreview.Source = image as ImageSource;
                }
                catch
                {
                    imgPreview.Source = null;
                    lblImgMsg.Content = "Couldn't open image";
                }
            }
        }
    }
}
